//
//  ViewController.m
//  propertyDemo
//
//  Created by apple on 16/5/5.
//  Copyright © 2016年 apple. All rights reserved.
//

#import "ViewController.h"


#import "BRPerson.h"
#import "BRSchool.h"
#import "BRStudent.h"
#import "BRTeacher.h"
#import "BRTest.h"

@interface ViewController ()
@property (nonatomic,strong) NSString *rstr;
@property (nonatomic,copy) NSString *cstr;
@end
/**
 * @author wangjun, 16-08-17 15:08:58
 *
 * 基本数据类型用assign，对象用strong，代理和UI控件用weak,字符串用copy！block也用copy
 */
@implementation ViewController
- (void)test{
    BRTest *test = [[BRTest alloc] init];
    test.name = @"测试";
    BRTest *copyTest = [test copy];
    BRTest *mutableTest = [test mutableCopy];
    NSLog(@"%@===%@===%@",test.name,copyTest.name,mutableTest.name);
    NSLog(@"%p====%p===%p",&test,&copyTest,&mutableTest);//变量本身的地址
    NSLog(@"%p====%p===%p",test,copyTest,mutableTest);//变量的值指向的地址
    NSLog(@"%p====%p===%p",test.name,copyTest.name,mutableTest.name);
    
    copyTest.name = @"haha";
    mutableTest.name = @"hello";
    NSLog(@"%@===%@===%@",test.name,copyTest.name,mutableTest.name);
}

- (void)teacher{
    BRTeacher *teacher = [[BRTeacher alloc] init];
    teacher.schoolName = @"北京大学";
    teacher.teacherName = @"李老师";
    NSLog(@"李老师所在的学校是%@",teacher.schoolName);
}
#pragma mark -完全深拷贝
- (void)deepCopy{
    NSMutableArray *array = [NSMutableArray array];
    for (int i=0; i<5; i++) {
        BRTest *test = [[BRTest alloc] init];
        test.name = [NSString stringWithFormat:@"test%d",(i+1)];
        [array addObject:test];
    }
    NSMutableArray *mutableArray = [array mutableCopy];
    NSMutableArray *copyItems = [[NSMutableArray alloc] initWithArray:array copyItems:YES];
    //数据归档再解档,实现完全拷贝
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array];
    NSMutableArray *archiveArr = [NSKeyedUnarchiver unarchiveObjectWithData:data];
    NSLog(@"%p",array);
    NSLog(@"%p",mutableArray);
    NSLog(@"%p",copyItems);
    NSLog(@"%p",archiveArr);
    NSLog(@"===========================================");
    NSLog(@"===========================================");
    NSLog(@"%p",array[0]);
    NSLog(@"%p",mutableArray[0]);
    NSLog(@"%p",copyItems[0]);
    NSLog(@"%p",archiveArr[0]);
    
    NSLog(@"===========================================");
    NSLog(@"===========================================");
    NSLog(@"%p",((BRTest *)array[0]).name);
    NSLog(@"%p",((BRTest *)mutableArray[0]).name);
    NSLog(@"%p",((BRTest *)copyItems[0]).name);
    NSLog(@"%p",((BRTest *)archiveArr[0]).name);
    
    BRTest *test = array[0];
    test.name = @"haha";
    NSLog(@"===========================================");
    NSLog(@"===========================================");
    NSLog(@"%p",((BRTest *)array[0]).name);
    NSLog(@"%p",((BRTest *)mutableArray[0]).name);
    NSLog(@"%p",((BRTest *)copyItems[0]).name);
    NSLog(@"%p",((BRTest *)archiveArr[0]).name);
    
    BRTest *test1 = copyItems[0];
    test1.name = @"hello";
    NSLog(@"===========================================");
    NSLog(@"===========================================");
    NSLog(@"%p",((BRTest *)array[0]).name);
    NSLog(@"%p",((BRTest *)mutableArray[0]).name);
    NSLog(@"%p",((BRTest *)copyItems[0]).name);
    NSLog(@"%p",((BRTest *)archiveArr[0]).name);

    NSLog(@"===========================================");
    NSLog(@"===========================================");
    NSLog(@"%@",((BRTest *)array[0]).name);
    NSLog(@"%@",((BRTest *)mutableArray[0]).name);
    NSLog(@"%@",((BRTest *)copyItems[0]).name);
    NSLog(@"%@",((BRTest *)archiveArr[0]).name);
}

- (void)viewDidLoad {
    [super viewDidLoad];
    [self deepCopy];
    //[self test];
   // [self teacher];
    
   // [self student];
    
    //浅拷贝 是不可变拷贝，也是指针拷贝,但如果数组中元素是字符串时，直接使用copy也是相当于深拷贝的
    //深拷贝，是可变拷贝，也是内容拷贝,与原有对象是互相独立，互相不影响的，即任何一方值有改变，另外一方都不会有任何改变
    //误解，认为浅拷贝就是用copy,深拷贝就是用mutableCopy,
    /*系统对象的copy与mutableCopy方法
     不管是集合类对象（数组，字典，set等）还是非集合类对象，接收到copy和mutableCopy消息时，都遵循一下准则
     1.copy返回的都是imutable(不可变)对象，所以如果对copy返回值使用mutable对象接口时就会crash
     2.mutablecopy返回mutable(可变)对象
     在非集合类对象中，对immutable对象进行copy操作，是指针复制，mutablecopy操作是内容复制，对mutable对象不管是进行copy还是mutablecopy操作是都是内容复制
     [immutableObject copy] 浅复制
     [immutableObject mutableCopy] 深复制
     [mutableObject copy] 深复制
     [mutableObject mutableCopy] 深复制
     在集合类对象中，对immutable对象进行copy操作时，是指针复制，mutableCopy是内容复制，对mutable对象进行copy和mutableCopy都是内容复制。但是集合对象的内容复制仅限于对象本身，对象元素的指针仍然是指针复制,也就是说不管是源头对象还是复制对象，其中m某一个对象元素的值发生改变，另外一个也会跟着改变
     [immutableObject copy] 浅复制
     [immutableObejct mutableCopy] 单层深复制
     [mutableObject copy] //单层深复制
     [mutableObejct mutableCopy]//单层深复制
     */
    
    NSMutableString *mutableStr = [[NSMutableString alloc] initWithString:@"iOS"];
    
    
    NSMutableString *copyStr = [mutableStr copy];
    copyStr = @"hello world";
    NSLog(@"%@",[copyStr class]);
   // [copyStr appendString:@" hello"];这里会闪退，因为用的是copy，返回的是不可变对象,深拷贝
    
    NSMutableString *mutableCopyStr = [mutableStr mutableCopy];//深拷贝，内容拷贝
    [mutableCopyStr appendString:@"world"];
    
    NSLog(@"%@--%@--%@",mutableStr,mutableCopyStr,copyStr);
    
    NSString *mstr = @"123";//如果字符串是NSString类型，copy还是strong 他返回的都是不可变类型，如果是NSMutableString类型，对其中任何一个重新赋值，会产生新的内存地址，所以他改变，对另外的对象没有影响，用strong是对其指针再次引用，retainCount+1,用copy则是深复制，和源头互相独立，互不影响
    self.rstr = mstr;
    self.cstr = mstr;
    //基础数据类型在栈上，对象在堆上
    NSLog(@"mStr:%p,%p",  mstr,&mstr);
    NSLog(@"copyStr:%p,%p", _cstr, &_cstr);
    NSLog(@"retainStr:%p,%p",   _rstr, &_rstr);
    
    NSLog(@"%@=========%@========%@",mstr,self.rstr,self.cstr);
    
    /**
     假如，mStr对象的地址为0x11，也就是0x11是@“abc”的首地址，mStr变量自身在内存中的地址为0x123；
     当把mStr赋值给retain的rStr时，rStr对象的地址为0x11，rStr变量自身在内存中的地址为0x124；rStr与mStr指向同样的地址，他们指向的是同一个对象@“abc”，这个对象的地址为0x11，所以他们的值是一样的。
     当把mStr赋值给copy的cStr时，cStr对象的地址为0x22，cStr变量自身在内存中的地址0x125；cStr与mStr指向的地址是不一样的，他们指向的是不同的对象，所以copy是深复制，一个新的对象，这个对象的地址为0x22，值为@“abc”。
     */
    mstr = @"234";//重新赋值，会发现mstr本身在内存中的地址没有变，还是指向mstr，但是他的值地址发生改变了，
    NSLog(@"mStr:%p,%p",  mstr,&mstr);
    NSLog(@"copyStr:%p,%p", _cstr, &_cstr);//前一个打印的地址是cstr这个变量的  值 的内存地址，即对值的引用，后一个打印的地址是cstr这个变量自身的内存地址
    NSLog(@"retainStr:%p,%p",   _rstr, &_rstr);
    
    NSLog(@"%@=========%@========%@",mstr,self.rstr,self.cstr);

    //数组元素是字符串
    NSMutableArray *modelsArray = [NSMutableArray arrayWithArray:@[@"123",@"456"]];
    //arr是不可变的
   // NSArray *arr = [modelsArray copy];
    
    NSMutableArray *arr = [modelsArray mutableCopy];
    arr[0] = @"jse3";
    
    NSLog(@"modelsArr =%@   ma=%@  ",modelsArray[0],arr[0]);
    //ma是可变的
    NSMutableArray *ma = [modelsArray mutableCopy];
    NSMutableArray *otherMa = [modelsArray copy];//因为用的是copy，返回的都应该是不可变对象，所以other其实是NSArray类型，如果修改元素的值会crash
    ma[0] = @"789";
    modelsArray[1] = @"hhaha";
    NSLog(@"%@",[otherMa class]);
    NSLog(@"modelsArr =%@   ma=%@   otherma=%@",modelsArray[1],ma[1],otherMa[1]);//打印结果显示，不管是哪个数组元素值发生变化，其他的数组的元素值都没有变化
    
    //数组元素是对象
    NSMutableArray *personArr = [[NSMutableArray alloc] init];
    BRPerson *person1 = [[BRPerson alloc] init];
    person1.name = @"lili";
    [personArr addObject:person1];
    
    BRPerson *person2 = [[BRPerson alloc] init];
    person2.name = @"lisa";
    [personArr addObject:person2];
    
    //浅拷贝
    NSArray *newArr = [personArr copy];
    BRPerson *p = newArr[0];
    p.name = @"lili的名字被修改了";
    NSLog(@"%@",((BRPerson *)personArr[0]).name);//打印结果为lili的名字被修改了，表示原来的数组中的元素value也修改了
    
    NSMutableArray *arr2 = [personArr mutableCopy];
    [arr2 removeObjectAtIndex:0];
    BRPerson *p2 = arr2[0];
    p2.name = @"sdsdsasdd";
    NSLog(@"%@ ---------- %@",((BRPerson *)newArr[0]).name,((BRPerson *)personArr[0]).name);//打印结果为lili的名字被修改了，表示原来的数组中的元素value也修改了
    
    //深拷贝，其实就是对数组中的所有对象都创建了一个新的对象
}

- (void)student{
    BRStudent *student = [BRStudent new];
    [student setAge:18];
    NSLog(@"%d",student.age);
    
    BRSchool *school = [BRSchool new];
    school.schoolName = @"xxxx";
    NSLog(@"%@",school.schoolName);
    
    BRTeacher *teacher = [[BRTeacher alloc] init];
   // teacher.teacherName = @"mr chen";//程序运行到这里会闪退，因为teacherName 被声明dynamic，然后你没有提供setter和getter方法，所以会闪退reason: '-[BRTeacher setTeacherName:]: unrecognized selector sent to instance
    
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end
